package dyyx.util;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.conn.routing.HttpRoute;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.pool.PoolStats;
import org.apache.http.util.EntityUtils;

public class HttpClientUtil {

	private static CloseableHttpClient httpClient;
	private static PoolingHttpClientConnectionManager cm;
	
	private static final int OK = 200; 
	
	
	private static final String Q = "?";
	private static final String AND = "&";

	
	
	static {
		try {
			init();
		} catch (Throwable e) {
			throw new RuntimeException("HttpClientUtil init error", e);
		}
	}

	private HttpClientUtil() {

	}

	private static void init() throws Exception {
		PoolingHttpClientConnectionManager cmTmp = new PoolingHttpClientConnectionManager();
		// Increase max total connection to 200
		cmTmp.setMaxTotal(100000);
		// Increase default max connection per route to 100
		cmTmp.setDefaultMaxPerRoute(1000);
		// Increase max connections for localhost:80 to 50
		// HttpHost localhost = new HttpHost("locahost", 80);
		// cm.setMaxPerRoute(new HttpRoute(localhost), 50);
	

		CloseableHttpClient httpClientTmp = HttpClients.custom().setConnectionManager(cmTmp).build();
		
		cm = cmTmp;
		httpClient = httpClientTmp;
	}
	public static String doGet(String url) throws Exception {
		return doGet(url,null);
	}

	
	public static String doGet(String url,Map<String, String> params) throws Exception {
		CloseableHttpResponse response = null;			
		try {
			List<NameValuePair> pairs = buildNameValuePairs(params);
            if(pairs!=null && !pairs.isEmpty()){
    			String querystr = URLEncodedUtils.format(pairs, CommUtil.UTF8);
    			
                //url = url +"?"+querystr;
    			url = buildQueryString(url,querystr);
    			//System.out.println("url="+url);
            }
			
            //System.out.println("doGet.url="+url);
    		HttpGet httpget = new HttpGet(url);

			
			//httpget.setHeader("Content-Type", "text/html;charset=UTF-8");
		    httpget.setHeader("Connection", "keep-alive");
		    
			response = httpClient.execute(httpget);
			StatusLine sl = response.getStatusLine();
			int statusCode = 0;
			if(sl!=null){
				statusCode = sl.getStatusCode();
				if(statusCode!=OK){
					throw new RuntimeException("statusCodeError,"+statusCode);
				}
			}
			RunStatusUtil.runStatus.updateCount("httpStatusCode-"+statusCode);
		    
			HttpEntity entity = response.getEntity();
			if(entity==null){
				return null;
			}
			return EntityUtils.toString(entity, CommUtil.UTF8);
		} finally {
			CommUtil.close(response);
		}
	}
	
	public static String doPost(String url,Map<String, String> params) throws Exception {
		CloseableHttpResponse response = null;			
		try {
			HttpPost http = new HttpPost(url);

			List<NameValuePair> pairs = buildNameValuePairs(params);
			
			if (pairs != null && !pairs.isEmpty()) {  
	            http.setEntity(new UrlEncodedFormEntity(pairs, CommUtil.UTF8)); 
	            //http.setParams(params);
	            
	            // System.out.println(EntityUtils.toString(http.getEntity()));
	            // System.out.println(http.getEntity().getContentType());
	            // System.out.println(http.getEntity().getContentEncoding());
  
	        }
			
			//http.setParams(params);
			
			// 不能设置 Content-Type !!!
		    //http.setHeader("Content-Type", "text/html;charset=UTF-8");
		    http.setHeader("Connection", "keep-alive");

			response = httpClient.execute(http);
			StatusLine sl = response.getStatusLine();
			int statusCode = 0;
			if(sl!=null){
				statusCode = sl.getStatusCode();
				if(statusCode!=OK){
					throw new RuntimeException("statusCodeError,"+statusCode);
				}

			}
			RunStatusUtil.runStatus.updateCount("httpStatusCode-"+statusCode);
		    
			HttpEntity entity = response.getEntity();
			if(entity==null){
				return null;
			}
			return EntityUtils.toString(entity, CommUtil.UTF8);
		} finally {
			CommUtil.close(response);
		}
	}
	
	
	public static String doPostBody(String url,String body) throws Exception {
		if(body==null){
			return null;
		}
		CloseableHttpResponse response = null;			
		try {
			HttpPost http = new HttpPost(url);

			
	        http.setEntity(new StringEntity(body,ContentType.APPLICATION_JSON)); 
	          
		    //http.setHeader("Content-Type", "text/html;charset=UTF-8");
		    http.setHeader("Connection", "keep-alive");

			response = httpClient.execute(http);
			StatusLine sl = response.getStatusLine();
			int statusCode = 0;
			if(sl!=null){
				statusCode = sl.getStatusCode();
				if(statusCode!=OK){
					throw new RuntimeException("statusCodeError,"+statusCode);
				}

			}
			RunStatusUtil.runStatus.updateCount("httpStatusCode-"+statusCode);
		    
			HttpEntity entity = response.getEntity();
			if(entity==null){
				return null;
			}
			return EntityUtils.toString(entity, CommUtil.UTF8);
		} finally {
			CommUtil.close(response);
		}
	}

	
	private static List<NameValuePair> buildNameValuePairs(Map<String, String> params){
		if(params==null || params.isEmpty()){
			return null;
		}
		Set<Map.Entry<String, String>> kvs = params.entrySet();
        String key;
        String value;
        List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
        for(Map.Entry<String, String> item:kvs){
        	key = item.getKey();
        	value = item.getValue();
        	if(StringUtils.isBlank(key) || StringUtils.isBlank(value)){
        		continue;
        	}
        	pairs.add(new BasicNameValuePair(key, value));
        }
		return pairs;
	}
	
	
	public static PoolStats getStats(){
		return cm.getTotalStats();
	}
	
	public static PoolStats getStats(String host,int port){
		return getStats(host,port,true);
	}

	
	public static PoolStats getStats(String host,int port,boolean http){
		String schema = "http";
		if(!http){
			schema = "https";
		}
		HttpHost httpHost = new HttpHost(host,port,schema);
		return cm.getStats(new HttpRoute(httpHost));
	}
	
	
	
	private static String buildQueryString(String url,String q){
		if(StringUtils.isBlank(q)){
			return url;
		}
		if(url.endsWith(AND)){
			return url + q;
		}
		if(url.indexOf(Q)<0){
			return url+Q+q;
		}
		return url + AND + q;
	}
	
	public static String buildQueryString(Map<String, String> params)throws Exception{
		if(params==null || params.isEmpty()){
			return null;
		}
		List<NameValuePair> nvps = new ArrayList<NameValuePair>(); 
		Set<Map.Entry<String, String>> nameAndValues = params.entrySet();
		String name = null;
		String value = null;
		for(Map.Entry<String,String> item:nameAndValues){
			name = item.getKey();
			value = item.getValue();
			if(StringUtils.isAnyBlank(name,value)){
				continue;
			}
	        nvps.add(new BasicNameValuePair(name, value));  

		}
		if(nvps.isEmpty()){
			return null;
		}
		return EntityUtils.toString(new UrlEncodedFormEntity(nvps, CommUtil.UTF8));
	}
	
	public static Map<String,Object> getInfo(){
		Map<String,Object> map = new HashMap<String,Object>();
		
		PoolStats totalPoolStats = cm.getTotalStats();
		int defaultMaxPerRoute = cm.getDefaultMaxPerRoute();
		int maxTotal = cm.getMaxTotal();
		
		map.put("totalPoolStats", totalPoolStats);
		map.put("defaultMaxPerRoute", defaultMaxPerRoute);
		map.put("maxTotal", maxTotal);

		return map;
	}

}
